﻿using static FreeTypeSharp.FT;
using static FreeTypeSharp.FT_LOAD;
using FreeTypeSharp;
using SkiaSharp;
using SkiaSharp.Views.Desktop;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
using static System.Net.WebRequestMethods;
using System.Windows.Forms;
using System.Net;

namespace Font2Outline
{
    public class FontUtils
    {
        public static int Width = 1600;
        public static int StrokeWidth = 2;

        #region FreeTypeSharp常量
        public const byte FT_CURVE_TAG_ON = 0x01;
        public const byte FT_CURVE_TAG_CONIC = 0x00;
        public const byte FT_CURVE_TAG_CUBIC = 0x02;
        public const byte FT_CURVE_TAG_HAS_SCANMODE = 0x04;
        public const byte FT_CURVE_TAG_TOUCH_X = 0x08;  /* reserved for TrueType hinter */
        public const byte FT_CURVE_TAG_TOUCH_Y = 0x10;  /* reserved for TrueType hinter */
        public static byte FT_CURVE_TAG(byte flag)
        {
            return (byte)(flag & 0x03);
        }

        public const byte FT_CURVE_TAG_TOUCH_BOTH = (byte)(FT_CURVE_TAG_TOUCH_X | FT_CURVE_TAG_TOUCH_Y);
        public const byte FT_Curve_Tag_On = FT_CURVE_TAG_ON;
        public const byte FT_Curve_Tag_Conic = FT_CURVE_TAG_CONIC;
        public const byte FT_Curve_Tag_Cubic = FT_CURVE_TAG_CUBIC;
        public const byte FT_Curve_Tag_Touch_X = FT_CURVE_TAG_TOUCH_X;
        public const byte FT_Curve_Tag_Touch_Y = FT_CURVE_TAG_TOUCH_Y;
        #endregion
        public static SKColor GetRandomColor()
        {
            Random random = new Random();
            byte r = (byte)random.Next(0, 255);
            byte g = (byte)random.Next(0, 255);
            byte b = (byte)random.Next(0, 255);
            SKColor randomColor = new SKColor(r, g, b);
            return randomColor;
        }


        public static unsafe Bitmap GetOutlineImage(string str, string fontPath)
        {
            char[] chArray = str.ToCharArray();
            SKBitmap bitmap = new SKBitmap(Width * chArray.Length, Width);//有多少个字符，就多少个*Width
            SKCanvas canvas = new SKCanvas(bitmap);
            canvas.Clear();
            for (int i = 0; i < chArray.Length; i++)
            {
                FT_LibraryRec_* library;
                FT_Error error = FT_Init_FreeType(&library);
                if (error != FT_Error.FT_Err_Ok)
                {
                    throw new Exception("load freetype errror!");
                }
                FT_FaceRec_* face;
                error = FT_New_Face(library, (byte*)Marshal.StringToHGlobalAnsi(fontPath), (IntPtr)0, &face);
                if (error == FT_Error.FT_Err_Unknown_File_Format)
                {
                    throw new Exception("FT_Err_Unknown_File_Format");
                }
                else if (error != FT_Error.FT_Err_Ok)
                {
                    throw new Exception(" another error code means that the font file could not  or simply that it is broken...");
                }
                error = FT_Set_Char_Size(
                                   face,      /* handle to face object           */
                                   0,         /* char_width in 1/64th of points  */
                                   Width * 64,   /* char_height in 1/64th of points */
                                   72,       /* horizontal device resolution    */
                                   72);      /* vertical device resolution      */
                //error = FT_Set_Pixel_Sizes(face, /* handle to face object */
                //                    0, /* pixel_width */
                //                    (uint)Width );/* pixel_height */

                //error = FT_Set_Char_Size(
                //                    face,      /* handle to face object           */
                //                    0,         /* char_width in 1/64th of points  */
                //                    16 * 64,   /* char_height in 1/64th of points */
                //                    300,       /* horizontal device resolution    */
                //                    300);      /* vertical device resolution      */
                if (error != FT_Error.FT_Err_Ok)
                {
                    throw new Exception("char size set error");
                }
                uint iGlyphIndex = FT_Get_Char_Index(face, (UIntPtr)chArray[i]);
                FT_LOAD loadflags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP;
                error = FT_Load_Glyph(face, iGlyphIndex, loadflags);
                if (error != FT_Error.FT_Err_Ok)
                {
                    throw new Exception("load glyph error");
                }
                FT_GlyphSlotRec_* pGlyphSlot = face->glyph;
                FT_Outline_ outline = pGlyphSlot->outline;
                FT_Vector_* point;
                FT_Vector_* limit;
                byte* tags;
                FT_Vector_ v_last;
                FT_Vector_ v_control;
                FT_Vector_ v_start;
                int first = 0;
                //遍历轮廓线数
                for (int n = 0; n < outline.n_contours; n++)
                {
                    int last = outline.contours[n];
                    limit = outline.points + last;
                    v_start = outline.points[first];
                    v_last = outline.points[last];
                    v_control = v_start;
                    point = outline.points + first;
                    tags = outline.tags + first;
                    byte tag = FT_CURVE_TAG(tags[0]);

                    PointF originalPoint = GetPointByFTVector(i, v_control);
                    PointF startPoint = originalPoint;

                    int onFirst = 0;
                    int conicOn = 0;
                    #region
                    //第一个轮廓从哪个点开始到哪个点结束
                    while (point < limit)
                    {
                        //判断下一个是什么
                        point++;//下一个点
                        tags++;//下一个点的Tag
                        tag = FT_CURVE_TAG(tags[0]);//下一个点的Tag
                        if (tag == FT_CURVE_TAG_ON)
                        {
                            //画直线
                            if (onFirst == 0)
                            {
                                PointF endPoint = GetPointByFTVector(i, point);

                                canvas.DrawLine(new SKPoint(startPoint.X, startPoint.Y), new SKPoint(endPoint.X, endPoint.Y), new SKPaint
                                {
                                    Color = GetRandomColor(),
                                    Style = SKPaintStyle.Stroke,
                                    StrokeWidth = StrokeWidth
                                });
                                //将游标后移
                                startPoint = endPoint;
                                onFirst = 0;
                                conicOn = 0;
                            }
                            //一个控制点的贝塞尔
                            else if (onFirst == 1)
                            {
                                point--;
                                PointF controlPoint = GetPointByFTVector(i, point);
                                point++;
                                PointF endPoint = GetPointByFTVector(i, point);

                                SKPath path1 = new SKPath();
                                path1.MoveTo(startPoint.X, startPoint.Y);
                                path1.QuadTo(controlPoint.X, controlPoint.Y, endPoint.X, endPoint.Y);
                                canvas.DrawPath(path1, new SKPaint
                                {
                                    Color = GetRandomColor(),
                                    Style = SKPaintStyle.Stroke,
                                    StrokeWidth = StrokeWidth
                                });
                                startPoint = endPoint;
                                onFirst = 0;
                                conicOn = 0;
                            }
                            //画两个控制点的贝塞尔曲线
                            else if (onFirst == 2)
                            {
                                //移动两次游标，得到第一个控制点
                                point--;
                                point--;
                                PointF controlPoint1 = GetPointByFTVector(i, point);
                                //往后再移动一下游标，得到第二个控制点
                                point++;
                                PointF controlPoint2 = GetPointByFTVector(i, point);
                                //再往后移一下，当前点
                                point++;
                                PointF endPoint = GetPointByFTVector(i, point);
                                //可以绘制路径了
                                SKPath path1 = new SKPath();
                                //起始位置
                                path1.MoveTo(startPoint.X, startPoint.Y);
                                path1.CubicTo(controlPoint1.X, controlPoint1.Y, controlPoint2.X, controlPoint2.Y, endPoint.X, endPoint.Y);
                                canvas.DrawPath(path1, new SKPaint
                                {
                                    Color = GetRandomColor(),
                                    Style = SKPaintStyle.Stroke,
                                    StrokeWidth = StrokeWidth
                                });
                                startPoint = endPoint;
                                onFirst = 0;
                                conicOn = 0;
                            }
                        }
                        else if (tag == FT_CURVE_TAG_CONIC)
                        {
                            conicOn++;
                            //连续两次FT_CURVE_TAG_CONIC,中间要建一个虚拟点
                            if (conicOn == 2)
                            {
                                //前一个点和当前点之前创建一个虚拟点
                                point--;
                                PointF frontPoint = GetPointByFTVector(i, point);
                                //当前点
                                point++;
                                PointF currentPoint = GetPointByFTVector(i, point);
                                //虚拟点
                                PointF virtualPoint = new PointF((frontPoint.X + currentPoint.X) / 2, (frontPoint.Y + currentPoint.Y) / 2);
                                //可以绘制一条一个控制点的贝塞尔
                                SKPath path2_1 = new SKPath();
                                path2_1.MoveTo(startPoint.X, startPoint.Y);
                                path2_1.QuadTo(frontPoint.X, frontPoint.Y, virtualPoint.X, virtualPoint.Y);
                                canvas.DrawPath(path2_1, new SKPaint
                                {
                                    Color = GetRandomColor(),
                                    Style = SKPaintStyle.Stroke,
                                    StrokeWidth = StrokeWidth
                                });
                                //记录开始点为这个虚拟点
                                startPoint = virtualPoint;
                                //重新计数
                                onFirst = 0;
                                onFirst++;
                                conicOn--;
                                continue;
                            }
                            //记录一个控制点
                            onFirst++;
                        }
                        else if (tag == FT_CURVE_TAG_CUBIC)
                        {
                            conicOn = 0;
                            //记录一个控制点
                            onFirst++;
                        }
                    }
                    //最后要绘制一条封闭的曲线，根据OnFirst判断前面有几个OFF
                    point++;
                    //前面0个OFF就画直线
                    if (onFirst == 0)
                    {
                        canvas.DrawLine(new SKPoint(startPoint.X, startPoint.Y), new SKPoint(originalPoint.X, originalPoint.Y), new SKPaint
                        {
                            Color = GetRandomColor(),
                            Style = SKPaintStyle.Stroke,
                            StrokeWidth = StrokeWidth
                        });
                    }
                    //前面一个OFF就画一个控制点的贝塞尔
                    else if (onFirst == 1)
                    {
                        point--;
                        PointF controlPoint = GetPointByFTVector(i, point);

                        SKPath path2 = new SKPath();
                        path2.MoveTo(startPoint.X, startPoint.Y);
                        path2.QuadTo(controlPoint.X, controlPoint.Y, originalPoint.X, originalPoint.Y);
                        canvas.DrawPath(path2, new SKPaint
                        {
                            Color = GetRandomColor(),
                            Style = SKPaintStyle.Stroke,
                            StrokeWidth = StrokeWidth
                        });
                    }
                    //前面两个OFF,画两个控制点的贝塞尔
                    else if (onFirst == 2)
                    {
                        point--;
                        point--;
                        PointF controlPoint1 = GetPointByFTVector(i, point);
                        point++;
                        PointF controlPoint2 = GetPointByFTVector(i, point);


                        SKPath path2 = new SKPath();
                        path2.MoveTo(startPoint.X, startPoint.Y);
                        path2.CubicTo(controlPoint1.X, controlPoint1.Y, controlPoint2.X, controlPoint2.Y, originalPoint.X, originalPoint.Y);
                        canvas.DrawPath(path2, new SKPaint
                        {
                            Color = GetRandomColor(),
                            Style = SKPaintStyle.Stroke,
                            StrokeWidth = StrokeWidth
                        });
                    }
                    first = last + 1;
                    #endregion
                }
                FT_Done_Face(face);
                FT_Done_FreeType(library);
            }
            canvas.Flush();
            Bitmap image = bitmap.ToBitmap();
            canvas.Dispose();
            bitmap.Dispose();
            //释放资源

            return image;
        }

        public static unsafe string GetOutlineSVG(string str, string fontPath)
        {
            char[] chArray = str.ToCharArray();
            //SVG头部
            StringBuilder svg = new StringBuilder();
            svg.AppendLine($"<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            svg.AppendLine($"<svg version=\"1.1\" id=\"图层_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" viewBox=\"0 0 {Width * chArray.Length} {Width}\" style=\"enable-background:new 0 0 {Width * chArray.Length} {Width};\" xml:space=\"preserve\">");
            svg.AppendLine($"<style type=\"text/css\">.st0{{fill:#FF0000;stroke:#000000;stroke-width:2;}}</style>");
            string path = "";
            for (int i = 0; i < chArray.Length; i++)
            {
                FT_LibraryRec_* library;
                FT_Error error = FT_Init_FreeType(&library);
                if (error != FT_Error.FT_Err_Ok)
                {
                    throw new Exception("load freetype errror!");
                }
                FT_FaceRec_* face;
                error = FT_New_Face(library, (byte*)Marshal.StringToHGlobalAnsi(fontPath), (IntPtr)0, &face);
                if (error == FT_Error.FT_Err_Unknown_File_Format)
                {
                    throw new Exception("FT_Err_Unknown_File_Format");
                }
                else if (error != FT_Error.FT_Err_Ok)
                {
                    throw new Exception(" another error code means that the font file could not  or simply that it is broken...");
                }
                error = FT_Set_Char_Size(
                                   face,      /* handle to face object           */
                                   0,         /* char_width in 1/64th of points  */
                                   Width * 64,   /* char_height in 1/64th of points */
                                   72,       /* horizontal device resolution    */
                                   72);      /* vertical device resolution      */
                //error = FT_Set_Pixel_Sizes(face, /* handle to face object */
                //                    0, /* pixel_width */
                //                    (uint)Width );/* pixel_height */

                //error = FT_Set_Char_Size(
                //                    face,      /* handle to face object           */
                //                    0,         /* char_width in 1/64th of points  */
                //                    16 * 64,   /* char_height in 1/64th of points */
                //                    300,       /* horizontal device resolution    */
                //                    300);      /* vertical device resolution      */
                if (error != FT_Error.FT_Err_Ok)
                {
                    throw new Exception("char size set error");
                }
                uint iGlyphIndex = FT_Get_Char_Index(face, (UIntPtr)chArray[i]);
                FT_LOAD loadflags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP;
                error = FT_Load_Glyph(face, iGlyphIndex, loadflags);
                if (error != FT_Error.FT_Err_Ok)
                {
                    throw new Exception("load glyph error");
                }
                FT_GlyphSlotRec_* pGlyphSlot = face->glyph;
                FT_Outline_ outline = pGlyphSlot->outline;


                FT_Vector_* point;
                FT_Vector_* limit;
                byte* tags;
                FT_Vector_ v_last;
                FT_Vector_ v_control;
                FT_Vector_ v_start;
                int first = 0;

                //遍历轮廓线数
                for (int n = 0; n < outline.n_contours; n++)
                {
                    int last = outline.contours[n];
                    limit = outline.points + last;
                    v_start = outline.points[first];
                    v_last = outline.points[last];
                    v_control = v_start;
                    point = outline.points + first;
                    tags = outline.tags + first;
                    byte tag = FT_CURVE_TAG(tags[0]);

                    PointF originalPoint = GetPointByFTVector(i, v_control);
                    PointF startPoint = originalPoint;

                    int onFirst = 0;
                    int conicOn = 0;
                    path += $"M{startPoint.X},{startPoint.Y} ";
                    #region
                    //第一个轮廓从哪个点开始到哪个点结束
                    while (point < limit)
                    {
                        //判断下一个是什么
                        point++;//下一个点
                        tags++;//下一个点的Tag
                        tag = FT_CURVE_TAG(tags[0]);//下一个点的Tag
                        if (tag == FT_CURVE_TAG_ON)
                        {
                            //画直线
                            if (onFirst == 0)
                            {
                                PointF endPoint = GetPointByFTVector(i, point);
                                path += $"L{endPoint.X},{endPoint.Y} ";
                                //将游标后移
                                startPoint = endPoint;
                                onFirst = 0;
                                conicOn = 0;
                            }
                            //一个控制点的贝塞尔
                            else if (onFirst == 1)
                            {
                                point--;
                                PointF controlPoint = GetPointByFTVector(i, point);
                                point++;
                                PointF endPoint = GetPointByFTVector(i, point);
                                path += $"Q{controlPoint.X},{controlPoint.Y},{endPoint.X},{endPoint.Y} ";
                                startPoint = endPoint;
                                onFirst = 0;
                                conicOn = 0;
                            }
                            //画两个控制点的贝塞尔曲线
                            else if (onFirst == 2)
                            {
                                //移动两次游标，得到第一个控制点
                                point--;
                                point--;
                                PointF controlPoint1 = GetPointByFTVector(i, point);
                                //往后再移动一下游标，得到第二个控制点
                                point++;
                                PointF controlPoint2 = GetPointByFTVector(i, point);
                                //再往后移一下，当前点
                                point++;
                                PointF endPoint = GetPointByFTVector(i, point);
                                //可以绘制路径了
                                path += $"C{controlPoint1.X},{controlPoint1.Y},{controlPoint2.X},{controlPoint2.Y},{endPoint.X},{endPoint.Y} ";
                                startPoint = endPoint;
                                onFirst = 0;
                                conicOn = 0;
                            }
                        }
                        else if (tag == FT_CURVE_TAG_CONIC)
                        {
                            conicOn++;
                            //连续两次FT_CURVE_TAG_CONIC,中间要建一个虚拟点
                            if (conicOn == 2)
                            {
                                //前一个点和当前点之前创建一个虚拟点
                                point--;
                                PointF frontPoint = GetPointByFTVector(i, point);
                                //当前点
                                point++;
                                PointF currentPoint = GetPointByFTVector(i, point);
                                //虚拟点
                                PointF virtualPoint = new PointF((frontPoint.X + currentPoint.X) / 2, (frontPoint.Y + currentPoint.Y) / 2);
                                //可以绘制一条一个控制点的贝塞尔
                                path += $"Q{frontPoint.X},{frontPoint.Y},{virtualPoint.X},{virtualPoint.Y} ";
                                //记录开始点为这个虚拟点
                                startPoint = virtualPoint;
                                //重新计数
                                onFirst = 0;
                                onFirst++;
                                conicOn--;
                                continue;
                            }
                            //记录一个控制点
                            onFirst++;
                        }
                        else if (tag == FT_CURVE_TAG_CUBIC)
                        {
                            conicOn = 0;
                            //记录一个控制点
                            onFirst++;
                        }
                    }
                    //最后要绘制一条封闭的曲线，根据OnFirst判断前面有几个OFF
                    point++;
                    //前面0个OFF就画直线
                    if (onFirst == 0)
                    {
                        path += $"L{originalPoint.X},{originalPoint.Y} ";
                    }
                    //前面一个OFF就画一个控制点的贝塞尔
                    else if (onFirst == 1)
                    {
                        point--;
                        PointF controlPoint = GetPointByFTVector(i, point);
                        path += $"Q{controlPoint.X},{controlPoint.Y},{originalPoint.X},{originalPoint.Y} ";
                    }
                    //前面两个OFF,画两个控制点的贝塞尔
                    else if (onFirst == 2)
                    {
                        point--;
                        point--;
                        PointF controlPoint1 = GetPointByFTVector(i, point);
                        point++;
                        PointF controlPoint2 = GetPointByFTVector(i, point);
                        path += $"C{controlPoint1.X},{controlPoint1.Y},{controlPoint2.X},{controlPoint2.Y},{originalPoint.X},{originalPoint.Y} ";
                    }
                    first = last + 1;
                    path += "Z";
                    #endregion
                }
                //释放资源
                FT_Done_Face(face);
                FT_Done_FreeType(library);
            }
            svg.AppendLine($"<path class=\"st0\" d=\"{path}\"></path>");
            svg.AppendLine($"</svg>");
            return svg.ToString();
        }

        public static unsafe Bitmap GetOutlineImage(char ch, string fontPath)
        {
            FT_LibraryRec_* library;
            FT_Error error = FT_Init_FreeType(&library);
            if (error != FT_Error.FT_Err_Ok)
            {
                throw new Exception("load freetype errror!");
            }
            FT_FaceRec_* face;
            error = FT_New_Face(library, (byte*)Marshal.StringToHGlobalAnsi(fontPath), (IntPtr)0, &face);
            if (error == FT_Error.FT_Err_Unknown_File_Format)
            {
                throw new Exception("FT_Err_Unknown_File_Format");
            }
            else if (error != FT_Error.FT_Err_Ok)
            {
                throw new Exception(" another error code means that the font file could not  or simply that it is broken...");
            }
            error = FT_Set_Char_Size(
                               face,      /* handle to face object           */
                               0,         /* char_width in 1/64th of points  */
                               Width * 64,   /* char_height in 1/64th of points */
                               72,       /* horizontal device resolution    */
                               72);      /* vertical device resolution      */
            //error = FT_Set_Pixel_Sizes(face, /* handle to face object */
            //                    0, /* pixel_width */
            //                    (uint)Width );/* pixel_height */

            //error = FT_Set_Char_Size(
            //                    face,      /* handle to face object           */
            //                    0,         /* char_width in 1/64th of points  */
            //                    16 * 64,   /* char_height in 1/64th of points */
            //                    300,       /* horizontal device resolution    */
            //                    300);      /* vertical device resolution      */
            if (error != FT_Error.FT_Err_Ok)
            {
                throw new Exception("char size set error");
            }
            uint iGlyphIndex = FT_Get_Char_Index(face, (UIntPtr)ch);
            FT_LOAD loadflags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP;
            error = FT_Load_Glyph(face, iGlyphIndex, loadflags);
            if (error != FT_Error.FT_Err_Ok)
            {
                throw new Exception("load glyph error");
            }
            FT_GlyphSlotRec_* pGlyphSlot = face->glyph;
            FT_Outline_ outline = pGlyphSlot->outline;

            SKBitmap bitmap = new SKBitmap(Width, Width);
            SKCanvas canvas = new SKCanvas(bitmap);
            canvas.Clear();
            FT_Vector_* point;
            FT_Vector_* limit;
            byte* tags;
            FT_Vector_ v_last;
            FT_Vector_ v_control;
            FT_Vector_ v_start;
            int first = 0;

            //遍历轮廓线数
            for (int n = 0; n < outline.n_contours; n++)
            {
                int last = outline.contours[n];
                limit = outline.points + last;
                v_start = outline.points[first];
                v_last = outline.points[last];
                v_control = v_start;
                point = outline.points + first;
                tags = outline.tags + first;
                byte tag = FT_CURVE_TAG(tags[0]);

                PointF originalPoint = GetPointByFTVector(v_control);
                PointF startPoint = originalPoint;

                int onFirst = 0;
                int conicOn = 0;
                #region
                //第一个轮廓从哪个点开始到哪个点结束
                while (point < limit)
                {
                    //判断下一个是什么
                    point++;//下一个点
                    tags++;//下一个点的Tag
                    tag = FT_CURVE_TAG(tags[0]);//下一个点的Tag
                    if (tag == FT_CURVE_TAG_ON)
                    {
                        //画直线
                        if (onFirst == 0)
                        {
                            PointF endPoint = GetPointByFTVector(point);

                            canvas.DrawLine(new SKPoint(startPoint.X, startPoint.Y), new SKPoint(endPoint.X, endPoint.Y), new SKPaint
                            {
                                Color = GetRandomColor(),
                                Style = SKPaintStyle.Stroke,
                                StrokeWidth = StrokeWidth
                            });
                            //将游标后移
                            startPoint = endPoint;
                            onFirst = 0;
                            conicOn = 0;
                        }
                        //一个控制点的贝塞尔
                        else if (onFirst == 1)
                        {
                            point--;
                            PointF controlPoint = GetPointByFTVector(point);
                            point++;
                            PointF endPoint = GetPointByFTVector(point);

                            SKPath path1 = new SKPath();
                            path1.MoveTo(startPoint.X, startPoint.Y);
                            path1.QuadTo(controlPoint.X, controlPoint.Y, endPoint.X, endPoint.Y);
                            canvas.DrawPath(path1, new SKPaint
                            {
                                Color = GetRandomColor(),
                                Style = SKPaintStyle.Stroke,
                                StrokeWidth = StrokeWidth
                            });
                            startPoint = endPoint;
                            onFirst = 0;
                            conicOn = 0;
                        }
                        //画两个控制点的贝塞尔曲线
                        else if (onFirst == 2)
                        {
                            //移动两次游标，得到第一个控制点
                            point--;
                            point--;
                            PointF controlPoint1 = GetPointByFTVector(point);
                            //往后再移动一下游标，得到第二个控制点
                            point++;
                            PointF controlPoint2 = GetPointByFTVector(point);
                            //再往后移一下，当前点
                            point++;
                            PointF endPoint = GetPointByFTVector(point);
                            //可以绘制路径了
                            SKPath path1 = new SKPath();
                            //起始位置
                            path1.MoveTo(startPoint.X, startPoint.Y);
                            path1.CubicTo(controlPoint1.X, controlPoint1.Y, controlPoint2.X, controlPoint2.Y, endPoint.X, endPoint.Y);
                            canvas.DrawPath(path1, new SKPaint
                            {
                                Color = GetRandomColor(),
                                Style = SKPaintStyle.Stroke,
                                StrokeWidth = StrokeWidth
                            });
                            startPoint = endPoint;
                            onFirst = 0;
                            conicOn = 0;
                        }
                    }
                    else if (tag == FT_CURVE_TAG_CONIC)
                    {
                        conicOn++;
                        //连续两次FT_CURVE_TAG_CONIC,中间要建一个虚拟点
                        if (conicOn == 2)
                        {
                            //前一个点和当前点之前创建一个虚拟点
                            point--;
                            PointF frontPoint = GetPointByFTVector(point);
                            //当前点
                            point++;
                            PointF currentPoint = GetPointByFTVector(point);
                            //虚拟点
                            PointF virtualPoint = new PointF((frontPoint.X + currentPoint.X) / 2, (frontPoint.Y + currentPoint.Y) / 2);
                            //可以绘制一条一个控制点的贝塞尔
                            SKPath path2_1 = new SKPath();
                            path2_1.MoveTo(startPoint.X, startPoint.Y);
                            path2_1.QuadTo(frontPoint.X, frontPoint.Y, virtualPoint.X, virtualPoint.Y);
                            canvas.DrawPath(path2_1, new SKPaint
                            {
                                Color = GetRandomColor(),
                                Style = SKPaintStyle.Stroke,
                                StrokeWidth = StrokeWidth
                            });
                            //记录开始点为这个虚拟点
                            startPoint = virtualPoint;
                            //重新计数
                            onFirst = 0;
                            onFirst++;
                            conicOn--;
                            continue;
                        }
                        //记录一个控制点
                        onFirst++;
                    }
                    else if (tag == FT_CURVE_TAG_CUBIC)
                    {
                        conicOn = 0;
                        //记录一个控制点
                        onFirst++;
                    }
                }
                //最后要绘制一条封闭的曲线，根据OnFirst判断前面有几个OFF
                point++;
                //前面0个OFF就画直线
                if (onFirst == 0)
                {
                    canvas.DrawLine(new SKPoint(startPoint.X, startPoint.Y), new SKPoint(originalPoint.X, originalPoint.Y), new SKPaint
                    {
                        Color = GetRandomColor(),
                        Style = SKPaintStyle.Stroke,
                        StrokeWidth = StrokeWidth
                    });
                }
                //前面一个OFF就画一个控制点的贝塞尔
                else if (onFirst == 1)
                {
                    point--;
                    PointF controlPoint = GetPointByFTVector(point);

                    SKPath path2 = new SKPath();
                    path2.MoveTo(startPoint.X, startPoint.Y);
                    path2.QuadTo(controlPoint.X, controlPoint.Y, originalPoint.X, originalPoint.Y);
                    canvas.DrawPath(path2, new SKPaint
                    {
                        Color = GetRandomColor(),
                        Style = SKPaintStyle.Stroke,
                        StrokeWidth = StrokeWidth
                    });
                }
                //前面两个OFF,画两个控制点的贝塞尔
                else if (onFirst == 2)
                {
                    point--;
                    point--;
                    PointF controlPoint1 = GetPointByFTVector(point);
                    point++;
                    PointF controlPoint2 = GetPointByFTVector(point);


                    SKPath path2 = new SKPath();
                    path2.MoveTo(startPoint.X, startPoint.Y);
                    path2.CubicTo(controlPoint1.X, controlPoint1.Y, controlPoint2.X, controlPoint2.Y, originalPoint.X, originalPoint.Y);
                    canvas.DrawPath(path2, new SKPaint
                    {
                        Color = GetRandomColor(),
                        Style = SKPaintStyle.Stroke,
                        StrokeWidth = StrokeWidth
                    });
                }
                first = last + 1;
                #endregion
            }
            canvas.Flush();
            Bitmap image = bitmap.ToBitmap();
            canvas.Dispose();
            bitmap.Dispose();
            //释放资源
            FT_Done_Face(face);
            FT_Done_FreeType(library);
            return image;
        }

        public static unsafe string GetOutlineSVG(char ch, string fontPath)
        {
            FT_LibraryRec_* library;
            FT_Error error = FT_Init_FreeType(&library);
            if (error != FT_Error.FT_Err_Ok)
            {
                throw new Exception("load freetype errror!");
            }
            FT_FaceRec_* face;
            error = FT_New_Face(library, (byte*)Marshal.StringToHGlobalAnsi(fontPath), (IntPtr)0, &face);
            if (error == FT_Error.FT_Err_Unknown_File_Format)
            {
                throw new Exception("FT_Err_Unknown_File_Format");
            }
            else if (error != FT_Error.FT_Err_Ok)
            {
                throw new Exception(" another error code means that the font file could not  or simply that it is broken...");
            }
            error = FT_Set_Char_Size(
                               face,      /* handle to face object           */
                               0,         /* char_width in 1/64th of points  */
                               Width * 64,   /* char_height in 1/64th of points */
                               72,       /* horizontal device resolution    */
                               72);      /* vertical device resolution      */
            //error = FT_Set_Pixel_Sizes(face, /* handle to face object */
            //                    0, /* pixel_width */
            //                    (uint)Width );/* pixel_height */

            //error = FT_Set_Char_Size(
            //                    face,      /* handle to face object           */
            //                    0,         /* char_width in 1/64th of points  */
            //                    16 * 64,   /* char_height in 1/64th of points */
            //                    300,       /* horizontal device resolution    */
            //                    300);      /* vertical device resolution      */
            if (error != FT_Error.FT_Err_Ok)
            {
                throw new Exception("char size set error");
            }
            uint iGlyphIndex = FT_Get_Char_Index(face, (UIntPtr)ch);
            FT_LOAD loadflags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP;
            error = FT_Load_Glyph(face, iGlyphIndex, loadflags);
            if (error != FT_Error.FT_Err_Ok)
            {
                throw new Exception("load glyph error");
            }
            FT_GlyphSlotRec_* pGlyphSlot = face->glyph;
            FT_Outline_ outline = pGlyphSlot->outline;

            StringBuilder svg = new StringBuilder();
            svg.AppendLine($"<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            svg.AppendLine($"<svg version=\"1.1\" id=\"图层_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" viewBox=\"0 0 {Width} {Width}\" style=\"enable-background:new 0 0 {Width} {Width};\" xml:space=\"preserve\">");
            svg.AppendLine($"<style type=\"text/css\">.st0{{fill:#FF0000;stroke:#000000;stroke-width:2;}}</style>");
            string path = "";
            FT_Vector_* point;
            FT_Vector_* limit;
            byte* tags;
            FT_Vector_ v_last;
            FT_Vector_ v_control;
            FT_Vector_ v_start;
            int first = 0;

            //遍历轮廓线数
            for (int n = 0; n < outline.n_contours; n++)
            {
                int last = outline.contours[n];
                limit = outline.points + last;
                v_start = outline.points[first];
                v_last = outline.points[last];
                v_control = v_start;
                point = outline.points + first;
                tags = outline.tags + first;
                byte tag = FT_CURVE_TAG(tags[0]);

                PointF originalPoint = GetPointByFTVector(v_control);
                PointF startPoint = originalPoint;

                int onFirst = 0;
                int conicOn = 0;
                path += $"M{startPoint.X},{startPoint.Y} ";
                #region
                //第一个轮廓从哪个点开始到哪个点结束
                while (point < limit)
                {
                    //判断下一个是什么
                    point++;//下一个点
                    tags++;//下一个点的Tag
                    tag = FT_CURVE_TAG(tags[0]);//下一个点的Tag
                    if (tag == FT_CURVE_TAG_ON)
                    {
                        //画直线
                        if (onFirst == 0)
                        {
                            PointF endPoint = GetPointByFTVector(point);
                            path += $"L{endPoint.X},{endPoint.Y} ";
                            //将游标后移
                            startPoint = endPoint;
                            onFirst = 0;
                            conicOn = 0;
                        }
                        //一个控制点的贝塞尔
                        else if (onFirst == 1)
                        {
                            point--;
                            PointF controlPoint = GetPointByFTVector(point);
                            point++;
                            PointF endPoint = GetPointByFTVector(point);
                            path += $"Q{controlPoint.X},{controlPoint.Y},{endPoint.X},{endPoint.Y} ";
                            startPoint = endPoint;
                            onFirst = 0;
                            conicOn = 0;
                        }
                        //画两个控制点的贝塞尔曲线
                        else if (onFirst == 2)
                        {
                            //移动两次游标，得到第一个控制点
                            point--;
                            point--;
                            PointF controlPoint1 = GetPointByFTVector(point);
                            //往后再移动一下游标，得到第二个控制点
                            point++;
                            PointF controlPoint2 = GetPointByFTVector(point);
                            //再往后移一下，当前点
                            point++;
                            PointF endPoint = GetPointByFTVector(point);
                            //可以绘制路径了
                            path += $"C{controlPoint1.X},{controlPoint1.Y},{controlPoint2.X},{controlPoint2.Y},{endPoint.X},{endPoint.Y} ";
                            startPoint = endPoint;
                            onFirst = 0;
                            conicOn = 0;
                        }
                    }
                    else if (tag == FT_CURVE_TAG_CONIC)
                    {
                        conicOn++;
                        //连续两次FT_CURVE_TAG_CONIC,中间要建一个虚拟点
                        if (conicOn == 2)
                        {
                            //前一个点和当前点之前创建一个虚拟点
                            point--;
                            PointF frontPoint = GetPointByFTVector(point);
                            //当前点
                            point++;
                            PointF currentPoint = GetPointByFTVector(point);
                            //虚拟点
                            PointF virtualPoint = new PointF((frontPoint.X + currentPoint.X) / 2, (frontPoint.Y + currentPoint.Y) / 2);
                            //可以绘制一条一个控制点的贝塞尔
                            path += $"Q{frontPoint.X},{frontPoint.Y},{virtualPoint.X},{virtualPoint.Y} ";
                            //记录开始点为这个虚拟点
                            startPoint = virtualPoint;
                            //重新计数
                            onFirst = 0;
                            onFirst++;
                            conicOn--;
                            continue;
                        }
                        //记录一个控制点
                        onFirst++;
                    }
                    else if (tag == FT_CURVE_TAG_CUBIC)
                    {
                        conicOn = 0;
                        //记录一个控制点
                        onFirst++;
                    }
                }
                //最后要绘制一条封闭的曲线，根据OnFirst判断前面有几个OFF
                point++;
                //前面0个OFF就画直线
                if (onFirst == 0)
                {
                    path += $"L{originalPoint.X},{originalPoint.Y} ";
                }
                //前面一个OFF就画一个控制点的贝塞尔
                else if (onFirst == 1)
                {
                    point--;
                    PointF controlPoint = GetPointByFTVector(point);
                    path += $"Q{controlPoint.X},{controlPoint.Y},{originalPoint.X},{originalPoint.Y} ";
                }
                //前面两个OFF,画两个控制点的贝塞尔
                else if (onFirst == 2)
                {
                    point--;
                    point--;
                    PointF controlPoint1 = GetPointByFTVector(point);
                    point++;
                    PointF controlPoint2 = GetPointByFTVector(point);
                    path += $"C{controlPoint1.X},{controlPoint1.Y},{controlPoint2.X},{controlPoint2.Y},{originalPoint.X},{originalPoint.Y} ";
                }
                first = last + 1;
                path += "Z";
                #endregion
            }
            svg.AppendLine($"<path class=\"st0\" d=\"{path}\"></path>");
            svg.AppendLine($"</svg>");
            //释放资源
            FT_Done_Face(face);
            FT_Done_FreeType(library);
            return svg.ToString();
        }

        private static PointF GetPointByFTVector(int index, FT_Vector_ vector)
        {
            PointF point = new PointF();
            point.X = vector.x / 64.0f + index * Width;
            point.Y = Width * 0.8f - vector.y / 64.0f;
            return point;
        }
        private static unsafe PointF GetPointByFTVector(int index, FT_Vector_* vector)
        {
            PointF point = new PointF();
            point.X = vector->x / 64.0f + index * Width;
            point.Y = Width * 0.8f - vector->y / 64.0f;
            return point;
        }


        private static PointF GetPointByFTVector(FT_Vector_ vector)
        {
            PointF point = new PointF();
            point.X = vector.x / 64.0f;
            point.Y = Width * 0.8f - vector.y / 64.0f;
            return point;
        }
        private static unsafe PointF GetPointByFTVector(FT_Vector_* vector)
        {
            PointF point = new PointF();
            point.X = vector->x / 64.0f;
            point.Y = Width * 0.8f - vector->y / 64.0f;
            return point;
        }


    }
}
